Object 是根父类,如何理解?
从继承的角度
- 如果一个类没有显示声明它的父类,那么它的父类就是 Object
- 说明所有类,所有对象都拥有 Object 类中的方法
- 每一个类的构造器,往上追踪都会调用到 Object 类中的无参构造
从多态角度
- Object 的变量(包括行参)可以接收任意类型的对象
- Object 数组,可以存储任意类型的对象
Object 中部分方法介绍
- getClass, 返回此 Object 的运行时类型。
- toString, 当打印一个对象时,默认调用这个对象的 toString() 方法。当对象与一个String 的值进行 + 操作时,也会调用 toString() 方法。
- hashCode, 返回对象的 hash 码
- equals, 指示其他对象是否与此对象相等。如果一个类没有重写 equals 方法,那么效果和 == 是一样的,比较的是两个对象的地址。如果不想使用 equals 来比较地址,而是比较属性的内容,那么需要重写 equals 方法。
- finalize, 当垃圾回收器确定不存在该对象的更多应用时,由对象的垃圾回收器调用此方法。
非静态代码块
特点
- 在创建对象的时候自动执行,每创建一个对象就执行一次。如果有多个非静态代码块,那么按顺序执行。
- 先于构造器执行。
- 与属性的显示赋值相比,他俩谁在前面谁就先执行。
实例初始化方法
- .java 代码编译为 .class 时,会把代码重新组装,如果类中有 n 个构造器,那么就会组装出 n 个实例初始化方法
- 实例初始化方法由三部分组成,分别是 (a)属性的显式赋值语句, (b)非静态代码块的语句, (c)构造器的语句。组装的顺序是(a) (b) 谁在前就谁先组装,(c) 排在最后。
- 创建子类对象的时候会先调用父类的实例初始化方法。
用实例初始化方法解释下面代码的执行顺序
Person.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.rexyan.object;
public class Person { private String name = getName();
{ System.out.println("父类非静态代码块"); }
Person(){ super(); System.out.println("父类无参构造"); }
Person(String name){ this.name = name; System.out.println("父类有参构造"); }
public String getName(){ System.out.println("父类属性显式赋值"); return "test"; } }
|
Student.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.rexyan.object;
public class Student extends Person{ private int age = getAge();
{ System.out.println("子类非静态代码块"); }
Student(){ super(); System.out.println("子类无参构造"); }
Student(int age){ this.age = age; System.out.println("子类有参构造"); }
public int getAge(){ System.out.println("子类属性显式赋值"); return 20; }
public static void main(String[] args){ Student s1 = new Student(); } }
|
输出
1 2 3 4 5 6
| 父类属性显式赋值 // 属性的显式赋值在静态代码块前面,所以先执行,即 (a) (b) 谁在前就谁先组装 父类非静态代码块 父类无参构造 // 最后是构造 子类属性显式赋值 // 父类结束后才是子类 子类非静态代码块 子类无参构造
|
解释: 实例初始化方法由三部分组成,分别是 (a)属性的显式赋值语句, (b)非静态代码块的语句, (c)构造器的语句。组装的顺序是(a) (b) 谁在前就谁先组装,(c) 排在最后。创建子类对象的时候会先调用父类的实例初始化方法。
保持父类不变,将子类改为如下内容:
Person.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.rexyan.object;
public class Person { private String name = getName();
{ System.out.println("父类非静态代码块"); }
Person(){ super(); System.out.println("父类无参构造"); }
Person(String name){ this.name = name; System.out.println("父类无参构造"); }
public String getName(){ System.out.println("父类属性显式赋值"); return "test"; } }
|
Student.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.rexyan.object;
public class Student extends Person{ private String name = getName();
{ System.out.println("子类非静态代码块"); }
Student(){ super(); System.out.println("子类无参构造"); }
Student(String name){ this.name = name; System.out.println("子类有参构造"); }
public String getName(){ System.out.println("子类属性显式赋值"); return "test"; }
public static void main(String[] args){ Student s1 = new Student(); } }
|
输出
1 2 3 4 5 6
| 子类属性显式赋值 // 这里执行父类中的 private String name = getName(); 方法。完整的应该是 this.getName()。this 代表的是当前长在创建的对象,现在正在创建的子类对象。那么其实调用的子类中的 getName() 方法。所以输出的是 “子类属性显式赋值”。 父类非静态代码块 父类无参构造 子类属性显式赋值 子类非静态代码块 子类无参构造
|